#!/usr/bin/python
# -*- coding: UTF-8 -*- 
"""个人常用工具函数

python3.8.10 win64  
python3.12   win64  √

"""

#获取脚本当前路径
from  pathlib import Path
# current_file_path = Path(__file__)
# current_directory = current_file_path.parent


# import win32con,win32api
# def get_Reg_key(path,key_):
#     """
#     获取注册表键值，需要安装pip包

#     Args:
#         path (_type_): 注册表路径
#         key_ (_type_): 注册表键

#     Returns:
#         _type_: 注册表值
    
#     Example:
#         reg=get_Reg_key("SOFTWARE\Classes\CATIA.Part\shell\open\command","")
#     """
#     reg_root = win32con.HKEY_LOCAL_MACHINE
#     #reg_root = win32con.HKEY_CLASSES_ROOT
#     reg_path = r'%s' % path
#     reg_flags = win32con.KEY_READ | win32con.KEY_WOW64_64KEY
#     # 读取键值
#     key = win32api.RegOpenKey(reg_root, reg_path, 0, reg_flags)
#     value, key_type = win32api.RegQueryValueEx(key, key_)
    
#     #关闭键
#     win32api.RegCloseKey(key)
#     return {"value":value}

#     # 测试注册表
# try:
#     reg=get_Reg_key("SOFTWARE\Classes\CATIA.Part\shell\open\command","")
# except Exception as e:  
#     print("找不到注册表信息，请检查Catia是否安装正确")
#     print(e)
# else:
#     print(reg)


#生成资源文件目录访问路径 转成二进制保存文件，暂时不需要
import sys
def resource_path(relative_path):
    if getattr(sys, 'frozen', False): #是否Bundle Resource
        base_path = sys._MEIPASS
    else:
        base_path = Path('.').resolve()
    return base_path / relative_path

# dir_setting = resource_path(Path("res").resolve()/"CATEnv2019") #导入时会被执行


# # 按进程名终止进程
# import win32api
# import win32con
# import win32com.client
# def terminate_process_by_name(process_name):
#     # 获取所有运行的进程
#     WMI = win32com.client.GetObject('winmgmts:')
#     processes = WMI.ExecQuery(f'SELECT * FROM Win32_Process WHERE Name="{process_name}"')

#     for process in processes:
#         process_id = process.Properties_('ProcessId').Value
#         try:
#             handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, False, process_id)
#             win32api.TerminateProcess(handle, -1)
#             win32api.CloseHandle(handle)
#         except Exception as e:
#             print(f"Failed to terminate {process_name} with PID {process_id}. Error: {e}")


# 启动一次软件并终止
import subprocess
def run_demo_exe(fpath,timewait):
    # global timeWait
    myPopenObj = subprocess.Popen([fpath], shell=True)
    try:
        myPopenObj.wait(timeout=timewait)
        # myPopenObj.wait()
        # if psutil.pid_exists(myPopenObj.pid) and psutil.pid_exists(myPopenObj.pid) in psutil.pids():
        #     print("程序运行")
    except Exception as e:
        #杀掉进程
        print("===== process timeout ======")
        myPopenObj.kill()
        myPopenObj.terminate()
        # myPopenObj.TerminateProcess()
        terminate_process_by_name("CNEXT.exe")
        # os.system("taskkill /im CNEXT.exe") 
        return None

# 获取桌面路径
def get_desk_p():
    home = Path.home()
    desktop = home / "Desktop"
    return desktop
    # https://blog.csdn.net/weixin_44224529/article/details/92393304

# 按照路径和关键字查找一个文件



# 使用rglob遍历目录中的所有文件
from pathlib import Path
def getFile(filepath,keyword):
    folder_path = Path(filepath)  # 替换为你的目录路径
    for file in folder_path.rglob("*"):
        if file.is_file() and (keyword+".txt") in file.name:
            fPath=str(file.resolve())
            print("所需文件路径为："+fPath)

# 读取txt内容
def getContext(fPath,keyword):
    env_f=open(fPath,errors='ignore')
    for line in env_f:
        if line.__contains__(keyword): 
            print(line)
# 写入txt
import datetime
def wTxt(fPath,content):
    env_f=open(fPath,mode="a")                            
    env_f.write(content)
    env_f.close #写入结束


# 以日志单独文件写入txt
def wLogbyTime(content):
    current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"{content}_{current_time}.json"
    # 将JSON数据写入文件
    with open(".\\socketlogs\\"+filename, 'w') as file:
        # json.dump(data, file, indent=4)
        content
    print(f"打印内容已保存到文件：{filename}")

# 压缩文件时间戳备份,复制，粘贴 3.8.10以后支持
import shutil,time
def zipbackup(root):
    shutil.make_archive(root+"备份"+str(time.time()),'zip',root_dir=root)
    shutil.copytree(dir_setting, CATUserSettingPath, dirs_exist_ok=True) #py38开始支持dir_exsit_OK参数
    # shutil.unpack_archive(CATUserSettingPath+"\CATEnv2019.zip",CATUserSettingPath)
  
"""
日志记录相关
"""   
import logging
from logging.handlers import RotatingFileHandler     
def createLogger():  
    # 配置日志记录器
    logger = logging.getLogger('tcp_server')
    logger.setLevel(logging.DEBUG)

    # 创建一个用于写入日志文件的处理器
    file_handler = RotatingFileHandler('tcpserve.log', maxBytes=1024*1024*5, backupCount=5)
    file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    file_handler.setFormatter(file_formatter)

    # 创建一个用于打印到控制台的处理器
    console_handler = logging.StreamHandler()
    console_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(console_formatter)

    # 将两个处理器添加到日志记录器
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)    
    return logger

# 去除ascii的1-31控制符
def remove_control_chars(s):  
    # 创建一个转换表，将ASCII 1-31（除了换行和回车）映射到空格  
    trans_table = str.maketrans({i: ' ' for i in range(1, 32) if i not in [10, 13]})  
    # 使用转换表替换字符串中的字符  
    return s.translate(trans_table)  
    """
    Example:  
        s = "Hello\x07World\x1b!\x01\x02\nNew Line\rCarriage Return"  
        print(remove_control_chars(s))  # 输出类似: Hello World !  New Line  
                                        # Carriage Return（注意：换行和回车被保留了
    """

# 加载dll写法
# dll = ctypes.cdll.LoadLibrary(Path(__file__).parent.parent/Path('focasx64/cppx64.dll'))

import subprocess
import json

def ping_ip(ip_address):
    """
    Ping 指定的 IP 地址。如果 ping 成功，返回 True；如果失败，返回 False。

    Args:
        ip_address (str): 要 ping 的 IP 地址。

    Returns:
        bool: ping 操作的成功与否。
    """
    try:
        # 对于 Windows 系统，使用 '-n' 参数；对于 Linux/Unix 系统，使用 '-c'
        # '-w' 参数指定超时时间（Windows），'-W' 参数指定超时时间（Linux/Unix）
        response = subprocess.run(['ping', '-c', '1', '-W', '2', ip_address], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        response = subprocess.run(['ping', '-n', '1', '-w', '2', ip_address], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        if response.returncode == 0:
            return True
        else:
            return False
    except Exception as e:
        print(f"Ping {ip_address} exception: {e}")
        return False

import socket
def get_local_ip():
    try:
        # 创建一个UDP套接字
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 连接到一个远端地址。这里的地址无需是有效的，因为数据不会被发送。
        s.connect(("8.8.8.8", 80))
        # 获取本地接口的IP地址
        ip = s.getsockname()[0]
    finally:
        # 关闭套接字
        s.close()
    return ip



# import win32print
# def get_printer_names():
#     """
#     获取本地打印机列表中名称

#     Returns:
#         _type_: 无
#     """
#     printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL)
#     printer_names = [printer[2] for printer in printers]
#     for printer in printer_names:
#         print(printer)

import subprocess
def open_Exe(objFilePath):
    """
    用后台进程打开一个exe程序

    Args:
        objFilePath (_type_): 程序的Path对象或者字符串路径

    Returns:
        _type_: myPopenObj，返回进程对象
    """
    return subprocess.Popen([objFilePath], shell=True)

def close_ExebyObj(myPopenObj):
    """
    按进程对象关闭打开的exe，需配合open_Exe()使用

    Args:
        myPopenObj (_type_): 由open_Exe()返回的进程对象
    """
    myPopenObj.kill()
    myPopenObj.terminate()
    3

from ctypes import string_at
def charPointer2string(char_prt):
    """
    处理C语言dll返回的const char* 指针，提取出字符串进行处理，
    并返回python字符串类型，需要手动释放指针内存！！！

    Args:
        char_prt (_type_): ctypes.POINTER(ctypes.c_char)

    Returns:
        _type_: Python String
    """
    string_content=string_at(char_prt).decode('utf-8',errors="replace").replace('\ufffd', 'INVALID')
    #记得需要在外部释放内存
    return string_content

if __name__ == '__main__':
    print("main直接运行")
    # print (dir_setting)
    print(ping_ip('192.168.88.134'))